home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / src / linux-headers-2.6.28-15 / drivers / scsi / script_asm.pl < prev   
Encoding:
Perl Script  |  2008-12-24  |  28.5 KB  |  985 lines

  1. #!/usr/bin/perl -s
  2.  
  3. # NCR 53c810 script assembler
  4. # Sponsored by 
  5. #       iX Multiuser Multitasking Magazine
  6. #
  7. # Copyright 1993, Drew Eckhardt
  8. #      Visionary Computing 
  9. #      (Unix and Linux consulting and custom programming)
  10. #      drew@Colorado.EDU
  11. #      +1 (303) 786-7975 
  12. #
  13. #   Support for 53c710 (via -ncr7x0_family switch) added by Richard
  14. #   Hirst <richard@sleepie.demon.co.uk> - 15th March 1997
  15. #
  16. #   This program is free software; you can redistribute it and/or modify
  17. #   it under the terms of the GNU General Public License as published by
  18. #   the Free Software Foundation; either version 2 of the License, or
  19. #   (at your option) any later version.
  20. #
  21. #   This program is distributed in the hope that it will be useful,
  22. #   but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24. #   GNU General Public License for more details.
  25. #
  26. #   You should have received a copy of the GNU General Public License
  27. #   along with this program; if not, write to the Free Software
  28. #   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29. #
  30. # TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
  31. #
  32.  
  33. # Basically, I follow the NCR syntax documented in the NCR53c710 
  34. # Programmer's guide, with the new instructions, registers, etc.
  35. # from the NCR53c810.
  36. #
  37. # Differences between this assembler and NCR's are that 
  38. # 1.  PASS, REL (data, JUMPs work fine), and the option to start a new 
  39. #    script,  are unimplemented, since I didn't use them in my scripts.
  40. # 2.  I also emit a script_u.h file, which will undefine all of 
  41. #     the A_*, E_*, etc. symbols defined in the script.  This 
  42. #    makes including multiple scripts in one program easier
  43. #     
  44. # 3.  This is a single pass assembler, which only emits 
  45. #    .h files.
  46. #
  47.  
  48.  
  49. # XXX - set these with command line options
  50. $debug = 0;        # Print general debugging messages
  51. $debug_external = 0;    # Print external/forward reference messages
  52. $list_in_array = 1;    # Emit original SCRIPTS assembler in comments in
  53.             # script.h
  54. #$prefix;        # (set by perl -s)
  55.                         # define all arrays having this prefix so we 
  56.             # don't have name space collisions after 
  57.             # assembling this file in different ways for
  58.             # different host adapters
  59.  
  60. # Constants
  61.  
  62.  
  63. # Table of the SCSI phase encodings
  64. %scsi_phases = (             
  65.     'DATA_OUT', 0x00_00_00_00, 'DATA_IN', 0x01_00_00_00, 'CMD', 0x02_00_00_00,
  66.     'STATUS', 0x03_00_00_00, 'MSG_OUT', 0x06_00_00_00, 'MSG_IN', 0x07_00_00_00
  67. );
  68.  
  69. # XXX - replace references to the *_810 constants with general constants
  70. # assigned at compile time based on chip type.
  71.  
  72. # Table of operator encodings
  73. # XXX - NCR53c710 only implements 
  74. #     move (nop) = 0x00_00_00_00
  75. #    or = 0x02_00_00_00
  76. #     and = 0x04_00_00_00
  77. #     add = 0x06_00_00_00
  78.  
  79. if ($ncr7x0_family) {
  80.   %operators = (
  81.     '|', 0x02_00_00_00, 'OR', 0x02_00_00_00,
  82.     '&', 0x04_00_00_00, 'AND', 0x04_00_00_00,
  83.     '+', 0x06_00_00_00
  84.   );
  85. }
  86. else {
  87.   %operators = (
  88.     'SHL',  0x01_00_00_00, 
  89.     '|', 0x02_00_00_00, 'OR', 0x02_00_00_00, 
  90.     'XOR', 0x03_00_00_00, 
  91.     '&', 0x04_00_00_00, 'AND', 0x04_00_00_00, 
  92.     'SHR', 0x05_00_00_00, 
  93.     # Note : low bit of the operator bit should be set for add with 
  94.     # carry.
  95.     '+', 0x06_00_00_00 
  96.   );
  97. }
  98.  
  99. # Table of register addresses
  100.  
  101. if ($ncr7x0_family) {
  102.   %registers = (
  103.     'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
  104.     'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
  105.     'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11,
  106.     'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
  107.     'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
  108.     'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23,
  109.     'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27,
  110.     'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
  111.     'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34, 'LCRC', 35,
  112.     'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
  113.     'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
  114.     'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
  115.     'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
  116.     'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
  117.     'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
  118.     'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
  119.   );
  120. }
  121. else {
  122.   %registers = (
  123.     'SCNTL0', 0, 'SCNTL1', 1, 'SCNTL2', 2, 'SCNTL3', 3,
  124.     'SCID', 4, 'SXFER', 5, 'SDID', 6, 'GPREG', 7,
  125.     'SFBR', 8, 'SOCL', 9, 'SSID', 10, 'SBCL', 11,
  126.     'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
  127.     'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
  128.     'ISTAT', 20,
  129.     'CTEST0', 24, 'CTEST1', 25, 'CTEST2', 26, 'CTEST3', 27,
  130.     'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
  131.     'DFIFO', 32, 'CTEST4', 33, 'CTEST5', 34, 'CTEST6', 35,
  132.     'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
  133.     'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
  134.     'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
  135.     'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
  136.     'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
  137.     'SCRATCHA0', 52, 'SCRATCHA1', 53, 'SCRATCHA2', 54, 'SCRATCHA3', 55,
  138.     'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
  139.     'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
  140.     'SIEN0', 64, 'SIEN1', 65, 'SIST0', 66, 'SIST1', 67,
  141.     'SLPAR', 68,           'MACNTL', 70, 'GPCNTL', 71,
  142.     'STIME0', 72, 'STIME1', 73, 'RESPID', 74, 
  143.     'STEST0', 76, 'STEST1', 77, 'STEST2', 78, 'STEST3', 79,
  144.     'SIDL', 80,
  145.     'SODL', 84,
  146.     'SBDL', 88,
  147.     'SCRATCHB0', 92, 'SCRATCHB1', 93, 'SCRATCHB2', 94, 'SCRATCHB3', 95
  148.   );
  149. }
  150.  
  151. # Parsing regular expressions
  152. $identifier = '[A-Za-z_][A-Za-z_0-9]*';        
  153. $decnum = '-?\\d+';
  154. $hexnum = '0[xX][0-9A-Fa-f]+';        
  155. $constant = "$hexnum|$decnum";
  156.  
  157. # yucky - since we can't control grouping of # $constant, we need to 
  158. # expand out each alternative for $value.
  159.  
  160. $value = "$identifier|$identifier\\s*[+\-]\\s*$decnum|".
  161.     "$identifier\\s*[+-]\s*$hexnum|$constant";
  162.  
  163. print STDERR "value regex = $value\n" if ($debug);
  164.  
  165. $phase = join ('|', keys %scsi_phases);
  166. print STDERR "phase regex = $phase\n" if ($debug);
  167. $register = join ('|', keys %registers);
  168.  
  169. # yucky - since %operators includes meta-characters which must
  170. # be escaped, I can't use the join() trick I used for the register
  171. # regex
  172.  
  173. if ($ncr7x0_family) {
  174.   $operator = '\||OR|AND|\&|\+';
  175. }
  176. else {
  177.   $operator = '\||OR|AND|XOR|\&|\+';
  178. }
  179.  
  180. # Global variables
  181.  
  182. %symbol_values = (%registers) ;        # Traditional symbol table
  183.  
  184. %symbol_references = () ;        # Table of symbol references, where
  185.                     # the index is the symbol name, 
  186.                     # and the contents a white space 
  187.                     # delimited list of address,size
  188.                     # tuples where size is in bytes.
  189.  
  190. @code = ();                # Array of 32 bit words for SIOP 
  191.  
  192. @entry = ();                # Array of entry point names
  193.  
  194. @label = ();                # Array of label names
  195.  
  196. @absolute = ();                # Array of absolute names
  197.  
  198. @relative = ();                # Array of relative names
  199.  
  200. @external = ();                # Array of external names
  201.  
  202. $address = 0;                # Address of current instruction
  203.  
  204. $lineno = 0;                # Line number we are parsing
  205.  
  206. $output = 'script.h';            # Output file
  207. $outputu = 'scriptu.h';
  208.  
  209. # &patch ($address, $offset, $length, $value) patches $code[$address]
  210. #     so that the $length bytes at $offset have $value added to
  211. #     them.  
  212.  
  213. @inverted_masks = (0x00_00_00_00, 0x00_00_00_ff, 0x00_00_ff_ff, 0x00_ff_ff_ff, 
  214.     0xff_ff_ff_ff);
  215.  
  216. sub patch {
  217.     local ($address, $offset, $length, $value) = @_;
  218.     if ($debug) {
  219.     print STDERR "Patching $address at offset $offset, length $length to $value\n";
  220.     printf STDERR "Old code : %08x\n", $code[$address];
  221.      }
  222.  
  223.     $mask = ($inverted_masks[$length] << ($offset * 8));
  224.    
  225.     $code[$address] = ($code[$address] & ~$mask) | 
  226.     (($code[$address] & $mask) + ($value << ($offset * 8)) & 
  227.     $mask);
  228.     
  229.     printf STDERR "New code : %08x\n", $code[$address] if ($debug);
  230. }
  231.  
  232. # &parse_value($value, $word, $offset, $length) where $value is 
  233. #     an identifier or constant, $word is the word offset relative to 
  234. #    $address, $offset is the starting byte within that word, and 
  235. #    $length is the length of the field in bytes.
  236. #
  237. # Side effects are that the bytes are combined into the @code array
  238. #    relative to $address, and that the %symbol_references table is 
  239. #     updated as appropriate.
  240.  
  241. sub parse_value {
  242.     local ($value, $word, $offset, $length) = @_;
  243.     local ($tmp);
  244.  
  245.     $symbol = '';
  246.  
  247.     if ($value =~ /^REL\s*\(\s*($identifier)\s*\)\s*(.*)/i) {
  248.     $relative = 'REL';
  249.     $symbol = $1;
  250.     $value = $2;
  251. print STDERR "Relative reference $symbol\n" if ($debug);
  252.     } elsif ($value =~ /^($identifier)\s*(.*)/) {
  253.     $relative = 'ABS';
  254.     $symbol = $1;
  255.     $value = $2;
  256. print STDERR "Absolute reference $symbol\n" if ($debug);
  257.     } 
  258.  
  259.     if ($symbol ne '') {
  260. print STDERR "Referencing symbol $1, length = $length in $_\n" if ($debug);
  261.          $tmp = ($address + $word) * 4 + $offset;
  262.     if ($symbol_references{$symbol} ne undef) {
  263.         $symbol_references{$symbol} = 
  264.         "$symbol_references{$symbol} $relative,$tmp,$length";
  265.     } else {
  266.         if (!defined($symbol_values{$symbol})) {
  267. print STDERR "forward $1\n" if ($debug_external);
  268.         $forward{$symbol} = "line $lineno : $_";
  269.         } 
  270.         $symbol_references{$symbol} = "$relative,$tmp,$length";
  271.     }
  272.     } 
  273.  
  274.     $value = eval $value;
  275.     &patch ($address + $word, $offset, $length, $value);
  276. }
  277.  
  278. # &parse_conditional ($conditional) where $conditional is the conditional
  279. # clause from a transfer control instruction (RETURN, CALL, JUMP, INT).
  280.  
  281. sub parse_conditional {
  282.     local ($conditional) = @_;
  283.     if ($conditional =~ /^\s*(IF|WHEN)\s*(.*)/i) {
  284.     $if = $1;
  285.     $conditional = $2;
  286.     if ($if =~ /WHEN/i) {
  287.         $allow_atn = 0;
  288.         $code[$address] |= 0x00_01_00_00;
  289.         $allow_atn = 0;
  290.         print STDERR "$0 : parsed WHEN\n" if ($debug);
  291.     } else {
  292.         $allow_atn = 1;
  293.         print STDERR "$0 : parsed IF\n" if ($debug);
  294.     }
  295.     } else {
  296.         die "$0 : syntax error in line $lineno : $_
  297.     expected IF or WHEN
  298. ";
  299.     }
  300.  
  301.     if ($conditional =~ /^NOT\s+(.*)$/i) {
  302.     $not = 'NOT ';
  303.     $other = 'OR';
  304.     $conditional = $1;
  305.     print STDERR "$0 : parsed NOT\n" if ($debug);
  306.     } else {
  307.     $code[$address] |= 0x00_08_00_00;
  308.     $not = '';
  309.     $other = 'AND'
  310.     }
  311.  
  312.     $need_data = 0;
  313.     if ($conditional =~ /^ATN\s*(.*)/i) {#
  314.     die "$0 : syntax error in line $lineno : $_
  315.     WHEN conditional is incompatible with ATN 
  316. " if (!$allow_atn);
  317.     $code[$address] |= 0x00_02_00_00;
  318.     $conditional = $1;
  319.     print STDERR "$0 : parsed ATN\n" if ($debug);
  320.     } elsif ($conditional =~ /^($phase)\s*(.*)/i) {
  321.     $phase_index = "\U$1\E";
  322.     $p = $scsi_phases{$phase_index};
  323.     $code[$address] |= $p | 0x00_02_00_00;
  324.     $conditional = $2;
  325.     print STDERR "$0 : parsed phase $phase_index\n" if ($debug);
  326.     } else {
  327.     $other = '';
  328.     $need_data = 1;
  329.     }
  330.  
  331. print STDERR "Parsing conjunction, expecting $other\n" if ($debug);
  332.     if ($conditional =~ /^(AND|OR)\s*(.*)/i) {
  333.     $conjunction = $1;
  334.     $conditional = $2;
  335.     $need_data = 1;
  336.     die "$0 : syntax error in line $lineno : $_
  337.         Illegal use of $1.  Valid uses are 
  338.         ".$not."<phase> $1 data
  339.         ".$not."ATN $1 data
  340. " if ($other eq '');
  341.     die "$0 : syntax error in line $lineno : $_
  342.     Illegal use of $conjunction.  Valid syntaxes are 
  343.         NOT <phase>|ATN OR data
  344.         <phase>|ATN AND data
  345. " if ($conjunction !~ /\s*$other\s*/i);
  346.     print STDERR "$0 : parsed $1\n" if ($debug);
  347.     }
  348.  
  349.     if ($need_data) {
  350. print STDERR "looking for data in $conditional\n" if ($debug);
  351.     if ($conditional=~ /^($value)\s*(.*)/i) {
  352.         $code[$address] |= 0x00_04_00_00;
  353.         $conditional = $2;
  354.         &parse_value($1, 0, 0, 1);
  355.         print STDERR "$0 : parsed data\n" if ($debug);
  356.     } else {
  357.     die "$0 : syntax error in line $lineno : $_
  358.     expected <data>.
  359. ";
  360.     }
  361.     }
  362.  
  363.     if ($conditional =~ /^\s*,\s*(.*)/) {
  364.     $conditional = $1;
  365.     if ($conditional =~ /^AND\s\s*MASK\s\s*($value)\s*(.*)/i) {
  366.         &parse_value ($1, 0, 1, 1);
  367.         print STDERR "$0 parsed AND MASK $1\n" if ($debug);
  368.         die "$0 : syntax error in line $lineno : $_
  369.     expected end of line, not \"$2\"
  370. " if ($2 ne '');
  371.     } else {
  372.         die "$0 : syntax error in line $lineno : $_
  373.     expected \",AND MASK <data>\", not \"$2\"
  374. ";
  375.     }
  376.     } elsif ($conditional !~ /^\s*$/) { 
  377.     die "$0 : syntax error in line $lineno : $_
  378.     expected end of line" . (($need_data) ? " or \"AND MASK <data>\"" : "") . "
  379.     not \"$conditional\"
  380. ";
  381.     }
  382. }
  383.  
  384. # Parse command line
  385. $output = shift;
  386. $outputu = shift;
  387.  
  388.     
  389. # Main loop
  390. while (<STDIN>) {
  391.     $lineno = $lineno + 1;
  392.     $list[$address] = $list[$address].$_;
  393.     s/;.*$//;                # Strip comments
  394.  
  395.  
  396.     chop;                # Leave new line out of error messages
  397.  
  398. # Handle symbol definitions of the form label:
  399.     if (/^\s*($identifier)\s*:(.*)/) {
  400.     if (!defined($symbol_values{$1})) {
  401.         $symbol_values{$1} = $address * 4;    # Address is an index into
  402.         delete $forward{$1};        # an array of longs
  403.         push (@label, $1);
  404.         $_ = $2;
  405.     } else {
  406.         die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
  407.     }
  408.     }
  409.  
  410. # Handle symbol definitions of the form ABSOLUTE or RELATIVE identifier = 
  411. # value
  412.     if (/^\s*(ABSOLUTE|RELATIVE)\s+(.*)/i) {
  413.     $is_absolute = $1;
  414.     $rest = $2;
  415.     foreach $rest (split (/\s*,\s*/, $rest)) {
  416.         if ($rest =~ /^($identifier)\s*=\s*($constant)\s*$/) {
  417.             local ($id, $cnst) = ($1, $2);
  418.         if ($symbol_values{$id} eq undef) {
  419.             $symbol_values{$id} = eval $cnst;
  420.             delete $forward{$id};
  421.             if ($is_absolute =~ /ABSOLUTE/i) {
  422.             push (@absolute , $id);
  423.             } else {
  424.             push (@relative, $id);
  425.             }
  426.         } else {
  427.             die "$0 : redefinition of symbol $id in line $lineno : $_\n";
  428.         }
  429.         } else {
  430.         die 
  431. "$0 : syntax error in line $lineno : $_
  432.         expected <identifier> = <value>
  433. ";
  434.         }
  435.     }
  436.     } elsif (/^\s*EXTERNAL\s+(.*)/i) {
  437.     $externals = $1;
  438.     foreach $external (split (/,/,$externals)) {
  439.         if ($external =~ /\s*($identifier)\s*$/) {
  440.         $external = $1;
  441.         push (@external, $external);
  442.         delete $forward{$external};
  443.         if (defined($symbol_values{$external})) {
  444.             die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
  445.         }
  446.         $symbol_values{$external} = $external;
  447. print STDERR "defined external $1 to $external\n" if ($debug_external);
  448.         } else {
  449.         die 
  450. "$0 : syntax error in line $lineno : $_
  451.     expected <identifier>, got $external
  452. ";
  453.         }
  454.     }
  455. # Process ENTRY identifier declarations
  456.     } elsif (/^\s*ENTRY\s+(.*)/i) {
  457.     if ($1 =~ /^($identifier)\s*$/) {
  458.         push (@entry, $1);
  459.     } else {
  460.         die
  461. "$0 : syntax error in line $lineno : $_
  462.     expected ENTRY <identifier>
  463. ";
  464.     }
  465. # Process MOVE length, address, WITH|WHEN phase instruction
  466.     } elsif (/^\s*MOVE\s+(.*)/i) {
  467.     $rest = $1;
  468.     if ($rest =~ /^FROM\s+($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) {
  469.         $transfer_addr = $1;
  470.         $with_when = $2;
  471.         $scsi_phase = $3;
  472. print STDERR "Parsing MOVE FROM $transfer_addr, $with_when $3\n" if ($debug);
  473.         $code[$address] = 0x18_00_00_00 | (($with_when =~ /WITH/i) ? 
  474.         0x00_00_00_00 : 0x08_00_00_00) | $scsi_phases{$scsi_phase};
  475.         &parse_value ($transfer_addr, 1, 0, 4);
  476.         $address += 2;
  477.     } elsif ($rest =~ /^($value)\s*,\s*(PTR\s+|)($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) {
  478.         $transfer_len = $1;
  479.         $ptr = $2;
  480.         $transfer_addr = $3;
  481.         $with_when = $4;
  482.         $scsi_phase = $5;
  483.         $code[$address] = (($with_when =~ /WITH/i) ? 0x00_00_00_00 : 
  484.         0x08_00_00_00)  | (($ptr =~ /PTR/i) ? (1 << 29) : 0) | 
  485.         $scsi_phases{$scsi_phase};
  486.         &parse_value ($transfer_len, 0, 0, 3);
  487.         &parse_value ($transfer_addr, 1, 0, 4);
  488.         $address += 2;
  489.     } elsif ($rest =~ /^MEMORY\s+(.*)/i) {
  490.         $rest = $1;
  491.         $code[$address] = 0xc0_00_00_00; 
  492.         if ($rest =~ /^($value)\s*,\s*($value)\s*,\s*($value)\s*$/) {
  493.         $count = $1;
  494.         $source = $2;
  495.         $dest =  $3;
  496. print STDERR "Parsing MOVE MEMORY $count, $source, $dest\n" if ($debug);
  497.         &parse_value ($count, 0, 0, 3);
  498.         &parse_value ($source, 1, 0, 4);
  499.         &parse_value ($dest, 2, 0, 4);
  500. printf STDERR "Move memory instruction = %08x,%08x,%08x\n", 
  501.         $code[$address], $code[$address+1], $code[$address +2] if
  502.         ($debug);
  503.         $address += 3;
  504.     
  505.         } else {
  506.         die 
  507. "$0 : syntax error in line $lineno : $_
  508.     expected <count>, <source>, <destination>
  509. "
  510.         }
  511.     } elsif ($1 =~ /^(.*)\s+(TO|SHL|SHR)\s+(.*)/i) {
  512. print STDERR "Parsing register to register move\n" if ($debug);
  513.         $src = $1;
  514.         $op = "\U$2\E";
  515.         $rest = $3;
  516.  
  517.         $code[$address] = 0x40_00_00_00;
  518.     
  519.         $force = ($op !~ /TO/i); 
  520.  
  521.  
  522. print STDERR "Forcing register source \n" if ($force && $debug);
  523.  
  524.         if (!$force && $src =~ 
  525.         /^($register)\s+(-|$operator)\s+($value)\s*$/i) {
  526. print STDERR "register operand  data8 source\n" if ($debug);
  527.         $src_reg = "\U$1\E";
  528.         $op = "\U$2\E";
  529.         if ($op ne '-') {
  530.             $data8 = $3;
  531.         } else {
  532.             die "- is not implemented yet.\n"
  533.         }
  534.         } elsif ($src =~ /^($register)\s*$/i) {
  535. print STDERR "register source\n" if ($debug);
  536.         $src_reg = "\U$1\E";
  537.         # Encode register to register move as a register | 0 
  538.         # move to register.
  539.         if (!$force) {
  540.             $op = '|';
  541.         }
  542.         $data8 = 0;
  543.         } elsif (!$force && $src =~ /^($value)\s*$/i) {
  544. print STDERR "data8 source\n" if ($debug);
  545.         $src_reg = undef;
  546.         $op = 'NONE';
  547.         $data8 = $1;
  548.         } else {
  549.         if (!$force) {
  550.             die 
  551. "$0 : syntax error in line $lineno : $_
  552.     expected <register>
  553.         <data8>
  554.         <register> <operand> <data8>
  555. ";
  556.         } else {
  557.             die
  558. "$0 : syntax error in line $lineno : $_
  559.     expected <register>
  560. ";
  561.         }
  562.         }
  563.         if ($rest =~ /^($register)\s*(.*)$/i) {
  564.         $dst_reg = "\U$1\E";
  565.         $rest = $2;
  566.         } else {
  567.         die 
  568. "$0 : syntax error in $lineno : $_
  569.     expected <register>, got $rest
  570. ";
  571.         }
  572.  
  573.         if ($rest =~ /^WITH\s+CARRY\s*(.*)/i) {
  574.         $rest = $1;
  575.         if ($op eq '+') {
  576.             $code[$address] |= 0x01_00_00_00;
  577.         } else {
  578.             die
  579. "$0 : syntax error in $lineno : $_
  580.     WITH CARRY option is incompatible with the $op operator.
  581. ";
  582.         }
  583.         }
  584.  
  585.         if ($rest !~ /^\s*$/) {
  586.         die
  587. "$0 : syntax error in $lineno : $_
  588.     Expected end of line, got $rest
  589. ";
  590.         }
  591.  
  592.         print STDERR "source = $src_reg, data = $data8 , destination = $dst_reg\n"
  593.         if ($debug);
  594.         # Note that Move data8 to reg is encoded as a read-modify-write
  595.         # instruction.
  596.         if (($src_reg eq undef) || ($src_reg eq $dst_reg)) {
  597.         $code[$address] |= 0x38_00_00_00 | 
  598.             ($registers{$dst_reg} << 16);
  599.         } elsif ($dst_reg =~ /SFBR/i) {
  600.         $code[$address] |= 0x30_00_00_00 |
  601.             ($registers{$src_reg} << 16);
  602.         } elsif ($src_reg =~ /SFBR/i) {
  603.         $code[$address] |= 0x28_00_00_00 |
  604.             ($registers{$dst_reg} << 16);
  605.         } else {
  606.         die
  607. "$0 : Illegal combination of registers in line $lineno : $_
  608.     Either source and destination registers must be the same,
  609.     or either source or destination register must be SFBR.
  610. ";
  611.         }
  612.  
  613.         $code[$address] |= $operators{$op};
  614.         
  615.         &parse_value ($data8, 0, 1, 1);
  616.         $code[$address] |= $operators{$op};
  617.         $code[$address + 1] = 0x00_00_00_00;# Reserved
  618.         $address += 2;
  619.     } else {
  620.         die 
  621. "$0 : syntax error in line $lineno : $_
  622.     expected (initiator) <length>, <address>, WHEN <phase>
  623.          (target) <length>, <address>, WITH <phase>
  624.          MEMORY <length>, <source>, <destination>
  625.          <expression> TO <register>
  626. ";
  627.     }
  628. # Process SELECT {ATN|} id, fail_address
  629.     } elsif (/^\s*(SELECT|RESELECT)\s+(.*)/i) {
  630.     $rest = $2;
  631.     if ($rest =~ /^(ATN|)\s*($value)\s*,\s*($identifier)\s*$/i) {
  632.         $atn = $1;
  633.         $id = $2;
  634.         $alt_addr = $3;
  635.         $code[$address] = 0x40_00_00_00 | 
  636.         (($atn =~ /ATN/i) ? 0x01_00_00_00 : 0);
  637.         $code[$address + 1] = 0x00_00_00_00;
  638.         &parse_value($id, 0, 2, 1);
  639.         &parse_value($alt_addr, 1, 0, 4);
  640.         $address += 2;
  641.     } elsif ($rest =~ /^(ATN|)\s*FROM\s+($value)\s*,\s*($identifier)\s*$/i) {
  642.         $atn = $1;
  643.         $addr = $2;
  644.         $alt_addr = $3;
  645.         $code[$address] = 0x42_00_00_00 | 
  646.         (($atn =~ /ATN/i) ? 0x01_00_00_00 : 0);
  647.         $code[$address + 1] = 0x00_00_00_00;
  648.         &parse_value($addr, 0, 0, 3);
  649.         &parse_value($alt_addr, 1, 0, 4);
  650.         $address += 2;
  651.         } else {
  652.         die 
  653. "$0 : syntax error in line $lineno : $_
  654.     expected SELECT id, alternate_address or 
  655.         SELECT FROM address, alternate_address or 
  656.         RESELECT id, alternate_address or
  657.         RESELECT FROM address, alternate_address
  658. ";
  659.     }
  660.     } elsif (/^\s*WAIT\s+(.*)/i) {
  661.         $rest = $1;
  662. print STDERR "Parsing WAIT $rest\n" if ($debug);
  663.     if ($rest =~ /^DISCONNECT\s*$/i) {
  664.         $code[$address] = 0x48_00_00_00;
  665.         $code[$address + 1] = 0x00_00_00_00;
  666.         $address += 2;
  667.     } elsif ($rest =~ /^(RESELECT|SELECT)\s+($identifier)\s*$/i) {
  668.         $alt_addr = $2;
  669.         $code[$address] = 0x50_00_00_00;
  670.         &parse_value ($alt_addr, 1, 0, 4);
  671.         $address += 2;
  672.     } else {
  673.         die
  674. "$0 : syntax error in line $lineno : $_
  675.     expected (initiator) WAIT DISCONNECT or 
  676.          (initiator) WAIT RESELECT alternate_address or
  677.          (target) WAIT SELECT alternate_address
  678. ";
  679.     }
  680. # Handle SET and CLEAR instructions.  Note that we should also do something
  681. # with this syntax to set target mode.
  682.     } elsif (/^\s*(SET|CLEAR)\s+(.*)/i) {
  683.     $set = $1;
  684.     $list = $2;
  685.     $code[$address] = ($set =~ /SET/i) ?  0x58_00_00_00 : 
  686.         0x60_00_00_00;
  687.     foreach $arg (split (/\s+AND\s+/i,$list)) {
  688.         if ($arg =~ /ATN/i) {
  689.         $code[$address] |= 0x00_00_00_08;
  690.         } elsif ($arg =~ /ACK/i) {
  691.         $code[$address] |= 0x00_00_00_40;
  692.         } elsif ($arg =~ /TARGET/i) {
  693.         $code[$address] |= 0x00_00_02_00;
  694.         } elsif ($arg =~ /CARRY/i) {
  695.         $code[$address] |= 0x00_00_04_00;
  696.         } else {
  697.         die 
  698. "$0 : syntax error in line $lineno : $_
  699.     expected $set followed by a AND delimited list of one or 
  700.     more strings from the list ACK, ATN, CARRY, TARGET.
  701. ";
  702.         }
  703.     }
  704.     $code[$address + 1] = 0x00_00_00_00;
  705.     $address += 2;
  706.     } elsif (/^\s*(JUMP|CALL|INT)\s+(.*)/i) {
  707.     $instruction = $1;
  708.     $rest = $2;
  709.     if ($instruction =~ /JUMP/i) {
  710.         $code[$address] = 0x80_00_00_00;
  711.     } elsif ($instruction =~ /CALL/i) {
  712.         $code[$address] = 0x88_00_00_00;
  713.     } else {
  714.         $code[$address] = 0x98_00_00_00;
  715.     }
  716. print STDERR "parsing JUMP, rest = $rest\n" if ($debug);
  717.  
  718. # Relative jump. 
  719.     if ($rest =~ /^(REL\s*\(\s*$identifier\s*\))\s*(.*)/i) { 
  720.         $addr = $1;
  721.         $rest = $2;
  722. print STDERR "parsing JUMP REL, addr = $addr, rest = $rest\n" if ($debug);
  723.         $code[$address]  |= 0x00_80_00_00;
  724.         &parse_value($addr, 1, 0, 4);
  725. # Absolute jump, requires no more gunk
  726.     } elsif ($rest =~ /^($value)\s*(.*)/) {
  727.         $addr = $1;
  728.         $rest = $2;
  729.         &parse_value($addr, 1, 0, 4);
  730.     } else {
  731.         die
  732. "$0 : syntax error in line $lineno : $_
  733.     expected <address> or REL (address)
  734. ";
  735.     }
  736.  
  737.     if ($rest =~ /^,\s*(.*)/) {
  738.         &parse_conditional($1);
  739.     } elsif ($rest =~ /^\s*$/) {
  740.         $code[$address] |= (1 << 19);
  741.     } else {
  742.         die
  743. "$0 : syntax error in line $lineno : $_
  744.     expected , <conditional> or end of line, got $1
  745. ";
  746.     }
  747.     
  748.     $address += 2;
  749.     } elsif (/^\s*(RETURN|INTFLY)\s*(.*)/i) {
  750.     $instruction = $1;
  751.     $conditional = $2; 
  752. print STDERR "Parsing $instruction\n" if ($debug);
  753.     $code[$address] = ($instruction =~ /RETURN/i) ? 0x90_00_00_00 :
  754.         0x98_10_00_00;
  755.     if ($conditional =~ /^,\s*(.*)/) {
  756.         $conditional = $1;
  757.         &parse_conditional ($conditional);
  758.     } elsif ($conditional !~ /^\s*$/) {
  759.         die
  760. "$0 : syntax error in line $lineno : $_
  761.     expected , <conditional> 
  762. ";
  763.     } else {
  764.         $code[$address] |= 0x00_08_00_00;
  765.     }
  766.        
  767.     $code[$address + 1] = 0x00_00_00_00;
  768.     $address += 2;
  769.     } elsif (/^\s*DISCONNECT\s*$/) {
  770.     $code[$address] = 0x48_00_00_00;
  771.     $code[$address + 1] = 0x00_00_00_00;
  772.     $address += 2;
  773. # I'm not sure that I should be including this extension, but 
  774. # what the hell?
  775.     } elsif (/^\s*NOP\s*$/i) {
  776.     $code[$address] = 0x80_88_00_00;
  777.     $code[$address + 1] = 0x00_00_00_00;
  778.     $address += 2;
  779. # Ignore lines consisting entirely of white space
  780.     } elsif (/^\s*$/) {
  781.     } else {
  782.     die 
  783. "$0 : syntax error in line $lineno: $_
  784.     expected label:, ABSOLUTE, CLEAR, DISCONNECT, EXTERNAL, MOVE, RESELECT,
  785.         SELECT SET, or WAIT
  786. ";
  787.     }
  788. }
  789.  
  790. # Fill in label references
  791.  
  792. @undefined = keys %forward;
  793. if ($#undefined >= 0) {
  794.     print STDERR "Undefined symbols : \n";
  795.     foreach $undef (@undefined) {
  796.     print STDERR "$undef in $forward{$undef}\n";
  797.     }
  798.     exit 1;
  799. }
  800.  
  801. @label_patches = ();
  802.  
  803. @external_patches = ();
  804.  
  805. @absolute = sort @absolute;
  806.  
  807. foreach $i (@absolute) {
  808.     foreach $j (split (/\s+/,$symbol_references{$i})) {
  809.     $j =~ /(REL|ABS),(.*),(.*)/;
  810.     $type = $1;
  811.     $address = $2;
  812.     $length = $3;
  813.     die 
  814. "$0 : $symbol $i has invalid relative reference at address $address,
  815.     size $length\n"
  816.     if ($type eq 'REL');
  817.         
  818.     &patch ($address / 4, $address % 4, $length, $symbol_values{$i});
  819.     }
  820. }
  821.  
  822. foreach $external (@external) {
  823. print STDERR "checking external $external \n" if ($debug_external);
  824.     if ($symbol_references{$external} ne undef) {
  825.     for $reference (split(/\s+/,$symbol_references{$external})) {
  826.         $reference =~ /(REL|ABS),(.*),(.*)/;
  827.         $type = $1;
  828.         $address = $2;
  829.         $length = $3;
  830.         
  831.         die 
  832. "$0 : symbol $label is external, has invalid relative reference at $address,
  833.     size $length\n"
  834.         if ($type eq 'REL');
  835.  
  836.         die 
  837. "$0 : symbol $label has invalid reference at $address, size $length\n"
  838.         if ((($address % 4) !=0) || ($length != 4));
  839.  
  840.         $symbol = $symbol_values{$external};
  841.         $add = $code[$address / 4];
  842.         if ($add eq 0) {
  843.         $code[$address / 4] = $symbol;
  844.         } else {
  845.         $add = sprintf ("0x%08x", $add);
  846.         $code[$address / 4] = "$symbol + $add";
  847.         }
  848.         
  849. print STDERR "referenced external $external at $1\n" if ($debug_external);
  850.     }
  851.     }
  852. }
  853.  
  854. foreach $label (@label) {
  855.     if ($symbol_references{$label} ne undef) {
  856.     for $reference (split(/\s+/,$symbol_references{$label})) {
  857.         $reference =~ /(REL|ABS),(.*),(.*)/;
  858.         $type = $1;
  859.         $address = $2;
  860.         $length = $3;
  861.  
  862.         if ((($address % 4) !=0) || ($length != 4)) {
  863.         die "$0 : symbol $label has invalid reference at $1, size $2\n";
  864.         }
  865.  
  866.         if ($type eq 'ABS') {
  867.         $code[$address / 4] += $symbol_values{$label};
  868.         push (@label_patches, $address / 4);
  869.         } else {
  870. # - The address of the reference should be in the second and last word
  871. #    of an instruction
  872. # - Relative jumps, etc. are relative to the DSP of the _next_ instruction
  873. #
  874. # So, we need to add four to the address of the reference, to get 
  875. # the address of the next instruction, when computing the reference.
  876.   
  877.         $tmp = $symbol_values{$label} - 
  878.             ($address + 4);
  879.         die 
  880. # Relative addressing is limited to 24 bits.
  881. "$0 : symbol $label is too far ($tmp) from $address to reference as 
  882.     relative/\n" if (($tmp >= 0x80_00_00) || ($tmp < -0x80_00_00));
  883.         $code[$address / 4] = $tmp & 0x00_ff_ff_ff;
  884.         }
  885.     }
  886.     }
  887. }
  888.  
  889. # Output SCRIPT[] array, one instruction per line.  Optionally 
  890. # print the original code too.
  891.  
  892. open (OUTPUT, ">$output") || die "$0 : can't open $output for writing\n";
  893. open (OUTPUTU, ">$outputu") || die "$0 : can't open $outputu for writing\n";
  894.  
  895. ($_ = $0) =~ s:.*/::;
  896. print OUTPUT "/* DO NOT EDIT - Generated automatically by ".$_." */\n";
  897. print OUTPUT "static u32 ".$prefix."SCRIPT[] = {\n";
  898. $instructions = 0;
  899. for ($i = 0; $i < $#code; ) {
  900.     if ($list_in_array) {
  901.     printf OUTPUT "/*\n$list[$i]\nat 0x%08x : */", $i;
  902.     }
  903.     printf OUTPUT "\t0x%08x,", $code[$i];
  904.     printf STDERR "Address $i = %x\n", $code[$i] if ($debug);
  905.     if ($code[$i + 1] =~ /\s*($identifier)(.*)$/) {
  906.     push (@external_patches, $i+1, $1);
  907.     printf OUTPUT "0%s,", $2
  908.     } else {
  909.     printf OUTPUT "0x%08x,",$code[$i+1];
  910.     }
  911.  
  912.     if (($code[$i] & 0xff_00_00_00) == 0xc0_00_00_00) {
  913.     if ($code[$i + 2] =~ /$identifier/) {
  914.         push (@external_patches, $i+2, $code[$i+2]);
  915.         printf OUTPUT "0,\n";
  916.     } else {
  917.         printf OUTPUT "0x%08x,\n",$code[$i+2];
  918.     }
  919.     $i += 3;
  920.     } else {
  921.     printf OUTPUT "\n";
  922.     $i += 2;
  923.     }
  924.     $instructions += 1;
  925. }
  926. print OUTPUT "};\n\n";
  927.  
  928. foreach $i (@absolute) {
  929.     printf OUTPUT "#define A_$i\t0x%08x\n", $symbol_values{$i};
  930.     if (defined($prefix) && $prefix ne '') {
  931.     printf OUTPUT "#define A_".$i."_used ".$prefix."A_".$i."_used\n";
  932.     printf OUTPUTU "#undef A_".$i."_used\n";
  933.     }
  934.     printf OUTPUTU "#undef A_$i\n";
  935.  
  936.     printf OUTPUT "static u32 A_".$i."_used\[\] __attribute((unused)) = {\n";
  937. printf STDERR "$i is used $symbol_references{$i}\n" if ($debug);
  938.     foreach $j (split (/\s+/,$symbol_references{$i})) {
  939.     $j =~ /(ABS|REL),(.*),(.*)/;
  940.     if ($1 eq 'ABS') {
  941.         $address = $2;
  942.         $length = $3;
  943.         printf OUTPUT "\t0x%08x,\n", $address / 4;
  944.     }
  945.     }
  946.     printf OUTPUT "};\n\n";
  947. }
  948.  
  949. foreach $i (sort @entry) {
  950.     printf OUTPUT "#define Ent_$i\t0x%08x\n", $symbol_values{$i};
  951.     printf OUTPUTU "#undef Ent_$i\n", $symbol_values{$i};
  952. }
  953.  
  954. #
  955. # NCR assembler outputs label patches in the form of indices into 
  956. # the code.
  957. #
  958. printf OUTPUT "static u32 ".$prefix."LABELPATCHES[] __attribute((unused)) = {\n";
  959. for $patch (sort {$a <=> $b} @label_patches) {
  960.     printf OUTPUT "\t0x%08x,\n", $patch;
  961. }
  962. printf OUTPUT "};\n\n";
  963.  
  964. $num_external_patches = 0;
  965. printf OUTPUT "static struct {\n\tu32\toffset;\n\tvoid\t\t*address;\n".
  966.     "} ".$prefix."EXTERNAL_PATCHES[] __attribute((unused)) = {\n";
  967. while ($ident = pop(@external_patches)) {
  968.     $off = pop(@external_patches);
  969.     printf OUTPUT "\t{0x%08x, &%s},\n", $off, $ident;
  970.     ++$num_external_patches;
  971. }
  972. printf OUTPUT "};\n\n";
  973.  
  974. printf OUTPUT "static u32 ".$prefix."INSTRUCTIONS __attribute((unused))\t= %d;\n", 
  975.     $instructions;
  976. printf OUTPUT "static u32 ".$prefix."PATCHES __attribute((unused))\t= %d;\n", 
  977.     $#label_patches+1;
  978. printf OUTPUT "static u32 ".$prefix."EXTERNAL_PATCHES_LEN __attribute((unused))\t= %d;\n",
  979.     $num_external_patches;
  980. close OUTPUT;
  981. close OUTPUTU;
  982.